承上篇
上篇實作完成執行結果如上圖所示,藍色區塊為該學生成績,紅色區塊為新增成績編輯畫面,全部程式皆在StudentView.kt
裡,接下來我們要將藍色及紅色部份分離出來。
GradeViewComponent.kt
,將藍色區塊程式碼剪下,完成程式如下 :package com.example.vok
import com.github.mvysny.karibudsl.v10.*
import com.vaadin.flow.component.HasComponents
import com.vaadin.flow.component.dependency.CssImport
import com.vaadin.flow.component.dependency.StyleSheet
import com.vaadin.flow.component.orderedlayout.VerticalLayout
class GradeViewComponent: KComposite() {
var studentId: Long = 0
set(value) {
field = value
refresh()
}
private lateinit var grades: VerticalLayout
private val root = ui{
verticalLayout {
isMargin = false
h2("成績")
grades = verticalLayout()
}
}
fun refresh() {
grades.removeAll()
Student.getById(studentId).grades.fetch().forEach {
grades.html("<p>" +
"<strong>學期:</strong>${it.description} " +
"<strong>國文:</strong>${it.mandarin} " +
"<strong>英文:</strong>${it.english} " +
"<strong>數學:</strong>${it.math} " +
"<strong>體育:</strong>${it.pe}" +
"</p>")
}
}
}
fun HasComponents.grandsViewComponent(block: GradeViewComponent.()->Unit = {}) = init(GradeViewComponent(), block)
這裡多了studentId
屬性值供外部設定,設定studentId
屬性後呼叫refresh()
方法,清除成績div區塊後,再讀取成績資料以html語法直接替換顯示。
GradeEditorComponent.kt
package com.example.vok
import com.github.mvysny.karibudsl.v10.*
import com.vaadin.flow.component.HasComponents
import com.vaadin.flow.component.button.Button
class GradeEditorComponent : KComposite() {
var gradeCreatedListener: () -> Unit = {}
lateinit var student: Student
private val gradeBinder = beanValidationBinder<Grade>()
private lateinit var addGradeButton: Button
private val root = ui {
verticalLayout {
text("新增成績")
textField("學期") {
bind(gradeBinder).bind(Grade::description)
placeholder = "第一學期"
}
numberField("國文") {
bind(gradeBinder).bind(Grade::mandarin)
}
numberField("英文") {
bind(gradeBinder).bind(Grade::english)
}
numberField("數學") {
bind(gradeBinder).bind(Grade::math)
}
numberField("體育") {
bind(gradeBinder).bind(Grade::pe)
}
addGradeButton = button("新增") {
onLeftClick { addGrade() }
}
}
}
private fun addGrade() {
val grade = Grade()
if (gradeBinder.validate().isOk && gradeBinder.writeBeanIfValid(grade)) {
grade.student_id = student.id
grade.save()
gradeBinder.readBean(Grade())
gradeCreatedListener()
}
}
}
fun HasComponents.gradeEditorComponent(block: GradeEditorComponent.() -> Unit = {}) =
init(GradeEditorComponent(), block)
StudentView.kt
package com.example.vok
import com.github.mvysny.karibudsl.v10.*
import com.vaadin.flow.component.Text
import com.vaadin.flow.component.icon.VaadinIcon
import com.vaadin.flow.router.BeforeEvent
import com.vaadin.flow.router.HasUrlParameter
import com.vaadin.flow.router.Route
import com.vaadin.flow.router.RouterLink
@Route("student", layout = MainLayout::class)
class StudentView: KComposite(), HasUrlParameter<Long> {
private lateinit var editLink: RouterLink
private lateinit var name: Text
private lateinit var gender: Text
private lateinit var birthday: Text
private lateinit var gradeView: GradeViewComponent
private lateinit var gradeEditor: GradeEditorComponent
private val root = ui {
verticalLayout {
routerLink(VaadinIcon.ARROW_LEFT, null, viewType = AllStudentsView::class)
div {
strong("姓名 : "); this@StudentView.name = text("")
}
div {
strong("性別 : "); this@StudentView.gender = text("")
}
div {
strong("生日 : "); this@StudentView.birthday = text("")
}
gradeView = grandsViewComponent()
gradeEditor = gradeEditorComponent {
gradeCreatedListener = { gradeView.refresh() }
}
editLink = routerLink(VaadinIcon.EDIT,null)
}
}
override fun setParameter(event: BeforeEvent?, studentId: Long) {
val student = Student.getById(studentId)
gradeView.studentId = studentId
gradeEditor.student = student
name.text = student.name
gender.text = student.gender.toString()
birthday.text = student.birthday.toString()
editLink.setRoute(EditStudent::class, student.id!!)
}
companion object {
fun navigateTo(studentId: Long) = navigateToView(StudentView::class, studentId)
}
}
gradeView
、gradeEditor
分別為藍色、紅色區塊
以下程式會使用到簡單 html、css 概念
除了可使用html()方法輸出 HTML 外,亦可使用 Karibu-DSL提供的其他方法。紅色區塊要將它改為div table 顯示
fun refresh() {
grades.removeAll()
grades.apply {
div("table") {
div("tr") {
div("td") { strong("學期") }
div("td") { strong("國文") }
div("td") { strong("英文") }
div("td") { strong("數學") }
div("td") { strong("體育") }
}
}
}
Student.getById(studentId).grades.fetch().forEach {
grades.apply {
div("table") {
div("tr") {
div("td") { label("${it.description}") }
div("td") { label("${it.mandarin}") }
div("td") { label("${it.english}") }
div("td") { label("${it.math}") }
div("td") { label("${it.pe}") }
}
}
}
}
div後面括號內為css class name ,表示我們需要一個 css檔。在Vaadin flow framework 專案結構,css檔放置在 web/frontend/,新增 table.css
.table {
display: table;
border-collapse: collapse;
width: 500px;
margin:0px;
}
/* tr */
.tr{
display: table-row; border:0px; margin:0px;
}
/* td , th */
.td {
display: table-cell;
width: 180px;
}
css 已經準備好了,該如何引入呢?請開啟 GradeViewComponent.kt
,在最前面加上標示
@CssImport("frontend://table.css")
class GradeViewComponent : KComposite() {
(略)
}
這樣就完成自訂樣式(style)的畫面了。雖然看起來似乎複雜了一點,但需要自訂Style時非常的好用,執行結如果下
參考資料 : css產生器
本日程式已上傳GitHub